package ga;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;


public class TS {   
	private HashMap<String,ContenidoTS> ts;
		
	private TS superior; 

	public TS(TS tsi) {
        superior = tsi;
        ts = new HashMap<String, ContenidoTS>();
    }
	
	public TS(TS tsi,HashMap<String,ContenidoTS> mapa) {
        superior = tsi;
        ts = mapa;
    }
	public TS Copia() {
		@SuppressWarnings("unchecked")
		TS nueva = new TS(superior,(HashMap<String,ContenidoTS>)ts.clone());
        return nueva;
    }

	public TS(){
		ts = new HashMap<String, ContenidoTS>();
		superior = null;
	}
	
    public Map<String, ContenidoTS> anadeId(String id, ContenidoTS reg) {
    	if(existeId(id)) {
    		return null;
        }
        else {
        	ts.put(id, reg);
            return ts;
        }
    }
    
    public Map<String, ContenidoTS> getTs() {
		return ts;
	}

	public void setTs(HashMap<String, ContenidoTS> ts) {
		this.ts = ts;
	}

    public TS aniade(String id, String clase,ObjTipo e, int direc, int nivel){
    	if(existeId(id)) {
    		if(nivelDe(id) != nivel && clase.equals("var"))
    		{
    			ContenidoTS r = new ContenidoTS(clase, direc, e, nivel, 0);
        		ts.put(id, r);
        		return this;
    		}
    		else
    			return this;
        }
        else {
        	ContenidoTS r = new ContenidoTS(clase, direc, e, nivel, 0);
        	ts.put(id, r);
            return this;
        }
    }    
    
    public int inicioDe(String id){
    	return this.ts.get(id).getInicio();
    }
 
    public boolean existeId(String id) {
    	if(ts.containsKey(id))
    		return true;
    	else
    	{
    		if(superior==null)
    			return false;
    		else
    			return superior.existeId(id);
    	}
    }
    
    public boolean existeIdTipo(String id) {
    	if(ts.containsKey(id))
    		return (ts.get(id).dameClase().equals("tipo"));
    	else
    	{
    		if(superior==null)
    			return false;
    		else
    			return superior.existeId(id);
    	}
    }
    
    public boolean existeIdUltNivel(String id) {
    	if(ts.containsKey(id))
    		return (ts.containsKey(id));
    	else
	    	return false;
    }
    
    public boolean existeTipo(ObjTipo tipo) {
    	
    	if(tipo.getTip()==ObjTipo.TipoDeObjTipo.array) return true;
    	if(tipo.getTip()==ObjTipo.TipoDeObjTipo.BOOLEAN) return true;
    	if(tipo.getTip()==ObjTipo.TipoDeObjTipo.INT) return true;
    	if(tipo.getTip()==ObjTipo.TipoDeObjTipo.proc) return true;
    	if(tipo.getTip()==ObjTipo.TipoDeObjTipo.punt) return true;
    	if(tipo.getTip()==ObjTipo.TipoDeObjTipo.reg) return true;
    	return false;
    }
       
    public int dirDe(String id) {
    	if(ts.containsKey(id))
    		return ts.get(id).dameDir();
    	else
    	{
    		if(superior==null)
    			return -1;
    		else
    			return superior.dirDe(id);
    	}
    }
    
    public ContenidoTS regDe(String id){
    	if(ts.containsKey(id))
    		return ts.get(id);
    	else
    	{
    		if(superior==null)
    			return null;
    		else
    			return superior.regDe(id);
    	}
    }
   
    public boolean tipoEsVar(ObjTipo o)
    {
    	
    	Iterator<Entry<String, ContenidoTS>> it = ts.entrySet().iterator();
    	while(it.hasNext()){
    		ContenidoTS cont = it.next().getValue();
    		if (cont.getObjTipo().equals(o)) {
			}
    			return cont.dameClase().equals("var");
    		}
    	if(superior==null) return false;
    	return superior.tipoEsVar(o);
    	
    }
    public String claseDe(String id){
    	if(ts.containsKey(id))
    	{
    		String tmp = ts.get(id).dameClase();
    		return tmp;
    	}
    	else
    	{
    		if(superior==null)
    			return null;
    		else
    			return superior.claseDe(id);
    	}
    }
    
    public ObjTipo tipoDe(String id){
    	if(ts.containsKey(id))
    	{
    		if(claseDe(id).equals("tipo"))
    			return new ObjTipo(id + " no es una variable");
    		return tipoDeRef(id);
    	}
    	else
    	{
    		if(superior==null)
    			return new ObjTipo("No existe el tipo: " + id + " declarado en la TS");
    		else
    			return superior.tipoDe(id);
    	}
    }
    
    public ObjTipo tipoDeRef(String id){
    	if(ts.containsKey(id))
    	{
    		String s;
    		//if(claseDe(id).equals("tipo"))
    			//return new ObjTipo(id + " no es una variable");
    		ObjTipo tmp =ts.get(id).getObjTipo();
    		
    		while(tmp.getTip()==ObjTipo.TipoDeObjTipo.ref)
    		{
    			s = tmp.getIdenRef();
    			if(ts.containsKey(s))
    				tmp=ts.get(s).getObjTipo();
    			else
    	    	{
    	    		if(superior==null)
    	    			return new ObjTipo("No existe el tipo: " + s + " declarado en la TS");
    	    		else
    	    			return superior.tipoDeRef(s);
    	    	}
    		}
    		return tmp;
    	}
    	else
    	{
    		if(superior==null)
    			return new ObjTipo("No existe el tipo: " + id + " declarado en la TS");
    		else
    			return superior.tipoDeRef(id);
    	}
    }
    public ObjTipo tipoDeProc(String id){
    	if(ts.containsKey(id))
    	{
    		ObjTipo tmp =ts.get(id).getObjTipo();
    		
    		while(tmp.getTip()==ObjTipo.TipoDeObjTipo.ref)
    		{
    			tmp=ts.get(tmp.getIdenRef()).getObjTipo();
    		}
    		return tmp;
    	}
    	else
    	{
    		if(superior==null)
    			return new ObjTipo("No existe el tipo: " + id + " declarado en la TS");
    		else
    			return superior.tipoDeProc(id);
    	}
    }
    
    
    public int nivelDe(String id){
    	if(ts.containsKey(id))
    		return ts.get(id).getNivel();
    	else
    	{
    		if(superior==null)
    			return -1;
    		else
    			return superior.nivelDe(id);
    	}
    }
}